package com.cloud.school.app.service.impl;

import com.cloud.school.app.entity.TbQuestion;
import com.cloud.school.app.mapstruct.IQuestionConvertMapper;
import com.cloud.school.app.model.*;
import com.cloud.school.app.repository.TbQuestionMapper;
import com.cloud.school.app.service.AnswerService;
import com.cloud.school.app.service.ImageService;
import com.cloud.school.app.service.QuestionService;
import com.cloud.school.app.service.UserService;
import com.cloud.school.app.util.IdWorker;
import com.cloud.school.app.util.Pager;
import com.github.pagehelper.PageHelper;
import com.google.common.collect.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import static com.cloud.school.app.config.CloudSchoolProperties.PAGE_PER_COUNT;
import static com.cloud.school.app.service.impl.AnswerServiceImpl.USER_NEW_ANSWER;

/**
 * @ClassName QuestionServiceImpl
 * @Description TODO
 * @Author 36297
 * @Date 2018/12/14 0:56
 * @Version 1.0
 */
@Service
public class QuestionServiceImpl implements QuestionService {
    @Autowired
    private TbQuestionMapper tbQuestionMapper;
    @Autowired
    private IQuestionConvertMapper questionConvertMapper;
    @Autowired
    private IdWorker questionIdWorker;
    @Autowired
    private AnswerService answerService;
    @Autowired
    private UserService userService;
    @Autowired
    private ImageService imageService;
    @Autowired
    private CacheService cacheService;

    @Override
    public Pager<QuestionModel> selectByUid(Long Uid, int pNo) {
        PageHelper.startPage(pNo, PAGE_PER_COUNT);
        TbQuestion question = new TbQuestion();
        question.setCreateUid(Uid);
        List<TbQuestion> questions = tbQuestionMapper.select(question);
        Pager result = Pager.build(questions);
        result.setResultList(questionConvertMapper.entityToModel(questions));
        return result;
    }

    @Override
    public Pager<QuestionModel> selectAll(int pNo) {
        PageHelper.startPage(pNo, PAGE_PER_COUNT);
        List<TbQuestion> questions = tbQuestionMapper.selectAll();
        Pager result = Pager.build(questions);
        result.setResultList(questionConvertMapper.entityToModel(questions));
        return result;
    }

    @Override
    public Pager<QuestionModel> selectDetailByUid(Long Uid, int pNo) {
        Pager<QuestionModel> result = selectByUid(Uid, pNo);
        appendUser(result.getResultList());
//        appendImage(result.getResultList());
//        appendAnswer(result.getResultList());
        appendAnswerCount(result.getResultList());
        result.setResultList(result.getResultList().stream().map(q -> {
            QuestionEngineModel qe = new QuestionEngineModel(q);
            qe.setNewAnswerCount(cacheService.hashGet(USER_NEW_ANSWER + q.getCreateUid(), String.valueOf(q.getId())));
            return qe;
        }).collect(Collectors.toList()));
        return result;
    }

    @Override
    public Pager<QuestionModel> selectAllDetail(int pNo) {
        Pager<QuestionModel> result = selectAll(pNo);
        appendUser(result.getResultList());
//        appendImage(result.getResultList());
//        appendAnswer(result.getResultList());
        appendAnswerCount(result.getResultList());
        result.setResultList(result.getResultList().stream().map(q -> {
            QuestionEngineModel qe = new QuestionEngineModel(q);
            qe.setNewAnswerCount(cacheService.hashGet(USER_NEW_ANSWER + q.getCreateUid(), String.valueOf(q.getId())));
            return qe;
        }).collect(Collectors.toList()));
        return result;
    }

    @Override
    public QuestionModel selectById(Long questionId) {
        return questionConvertMapper.entityToModel(tbQuestionMapper.selectByPrimaryKey(questionId));
    }

    @Override
    public QuestionModel selectDetailById(Long questionId) {
        QuestionModel result = selectById(questionId);
        if (result == null) {
            return null;
        }
        List<QuestionModel> questionModels = Lists.newArrayList(result);
        appendUser(questionModels);
        appendImage(questionModels);
        appendAnswer(questionModels);
        cacheService.hashDelete(USER_NEW_ANSWER + result.getCreateUid(), String.valueOf(result.getId()));
        return result;
    }

    @Override
    public QuestionModel selectDetailWithoutAnswerFormatById(Long questionId) {
        QuestionModel result = selectById(questionId);
        if (result == null) {
            return null;
        }
        List<QuestionModel> questionModels = Lists.newArrayList(result);
        appendUser(questionModels);
        appendImage(questionModels);
        appendAnswerWithoutFormat(questionModels);
        cacheService.hashDelete(USER_NEW_ANSWER + result.getCreateUid(), String.valueOf(result.getId()));
        return result;
    }

    private void appendUser(List<QuestionModel> result) {
        List<Long> uids = result.stream().map(s -> s.getCreateUid()).filter(id -> id != null).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(uids)) {
            Map<Long, UserModel> userModelMap = userService.queryDetailByIds(uids).stream().collect(Collectors.toMap(UserModel::getId, u -> u));
            result.forEach(q -> q.setCreator(userModelMap.get(q.getCreateUid())));
        }
    }

    private void appendImage(List<QuestionModel> result) {
        List<Long> imageIds = result.stream().map(s -> s.getImages()).flatMap(images -> images.stream()).filter(id -> id != null).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(imageIds)) {
            Map<Long, ImageModel> imageModelMap = imageService.seleteByIds(imageIds).stream().collect(Collectors.toMap(ImageModel::getId, i -> i));
            result.forEach(q -> q.setImageModels(getByIdsString(imageModelMap, q.getImages())));
        }
    }

    private void appendAnswer(List<QuestionModel> result) {
        List<Long> questionIds = result.stream().map(q -> q.getId()).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(questionIds)) {
            List<AnswerModel> answerModels = answerService.queryDetailByQuestionIds(questionIds);
            result.forEach(q -> q.setAnswerModels(answerListFormat(answerModels).get(q.getId())));
        }
    }

    private void appendAnswerWithoutFormat(List<QuestionModel> result) {
        List<Long> questionIds = result.stream().map(q -> q.getId()).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(questionIds)) {
            Map<Long, List<AnswerModel>> longListMap = answerService.queryDetailByQuestionIds(questionIds).stream().collect(Collectors.groupingBy(AnswerModel::getQuestionId));
            result.forEach(q -> q.setAnswerModels(longListMap.get(q.getId())));
        }
    }

    private void appendAnswerCount(List<QuestionModel> result) {
        List<Long> questionIds = result.stream().map(q -> q.getId()).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(questionIds)) {
            Map<Long, Long> answerCountMaps = answerService.selectCountGroupByQuestionIdIn(questionIds);
            result.forEach(q -> q.setAnswerCount(null == answerCountMaps.get(q.getId()) ? 0 : answerCountMaps.get(q.getId()).intValue()));
        }
    }

    private Map<Long, List<AnswerModel>> answerListFormat(List<AnswerModel> answerModels) {
        Map<Long, List<AnswerModel>> longAnswerListMap = answerModels.stream().filter(a -> a.getPrevId() != null).collect(Collectors.groupingBy(a -> a.getPrevId()));
        Map<Long, AnswerModel> longAnswerModelMap = answerModels.stream().collect(Collectors.toMap(a -> a.getId(), a -> a));
        longAnswerListMap.forEach((k, v) -> Optional.ofNullable(longAnswerModelMap.get(k)).ifPresent(a -> a.setAnswerModels(v)));
        return answerModels.stream().filter(a -> a.getPrevId() == null).collect(Collectors.groupingBy(a -> a.getQuestionId()));
    }

    private List<ImageModel> getByIdsString(Map<Long, ImageModel> imageModelMap, List<Long> ids) {
        List<ImageModel> list = Lists.newArrayList();
        ids.forEach(id -> list.add(imageModelMap.get(id)));
        return list;
    }

    @Override
    @Transactional
    public boolean save(QuestionModel questionModel) {
        TbQuestion question = questionConvertMapper.modelToEntity(questionModel);
        question.setId(questionIdWorker.nextId());
        question.setCreateTime(System.currentTimeMillis());
        return tbQuestionMapper.insertSelective(question) > 0;
    }

    @Override
    @Transactional
    public boolean deleteById(Long questionId) {
        QuestionModel questionModel = selectById(questionId);
        if (questionModel != null && questionModel.getImages() != null) {
            questionModel.getImages().forEach(id -> imageService.delete(id));
        }
        cacheService.hashDelete(USER_NEW_ANSWER + questionModel.getCreateUid(), String.valueOf(questionModel.getId()));
        answerService.deleteByQuestionId(questionId);
        return tbQuestionMapper.deleteByPrimaryKey(questionId) > 0;
    }
}
